﻿namespace KinonekoSoftware.CodariaDB.Documents.Shenanigans.Talking
{
    public sealed class TalkingEngine : CharacterEngine, IInstanceAssemblyFactory
    {

        #region Emoji

        public IEnumerable<Emoji> GetEmojis() => EmojiDB.FindAll();

        public void AddEmoji(Emoji emoji)
        {
            if (emoji is null)
            {
                return;
            }

            if (string.IsNullOrEmpty(emoji.Id))
            {
                return;
            }

            EmojiDB.Insert(emoji);
            Modified();
        }

        public void RemoveEmoji(Emoji emoji)
        {
            if (emoji is null)
            {
                return;
            }

            var id = emoji.Id;

            if (string.IsNullOrEmpty(id))
            {
                return;
            }

            EmojiDB.Delete(id);
            Modified();
        }

        #endregion

        #region Channels
        
        public bool HasChannel(string id) => !string.IsNullOrEmpty(id) && ChannelDB.HasID(id);

        public void AddChannel(TalkingBase channel)
        {
            if (channel is null)
            {
                return;
            }

            if (string.IsNullOrEmpty(channel.Id))
            {
                return;
            }

            ChannelDB.Insert(channel);
            Modified();
        }
        
        
        public void UpdateChannel(TalkingBase channel)
        {
            if (channel is null)
            {
                return;
            }

            if (string.IsNullOrEmpty(channel.Id))
            {
                return;
            }

            ChannelDB.Update(channel);
            Modified();
        }

        public void RemoveChannel(TalkingBase channel)
        {
            if (channel is null)
            {
                return;
            }

            var id = channel.Id;

            if (string.IsNullOrEmpty(id))
            {
                return;
            }

            ChannelDB.Delete(id);
            Modified();
        }

        /// <summary>
        /// 获取相关联的所有聊天频道。
        /// </summary>
        /// <param name="id">角色ID</param>
        /// <param name="type">指定要获得的频道类型</param>
        /// <returns>返回聊天频道</returns>
        public IEnumerable<TalkingBase> GetChannels(string id, TalkingChannelType type)
        {
            if (string.IsNullOrEmpty(id))
            {
                return Array.Empty<TalkingBase>();
            }
            
            var members = MemberDB.Find(x => x.MemberID == id)
                                  .Select(x => x.ChannelID)
                                  .ToHashSet();
            var channels = ChannelDB.Find(x => members.Contains(x.Id) && x.Type == type);
            return channels;
        }
        
        /// <summary>
        /// 获取相关联的所有聊天频道。
        /// </summary>
        /// <param name="type">指定要获得的频道类型</param>
        /// <returns>返回聊天频道</returns>
        public IEnumerable<TalkingBase> GetChannels(TalkingChannelType type)
        {
            var channels = ChannelDB.Find(x => x.Type == type);
            return channels;
        }

        #endregion

        #region Members

        public void AddMember(Character owner, TalkingBase talking)
        {


            if (owner is null || talking is null)
            {
                return;
            }

            var member = new TalkingMember
            {
                Id        = ID.Get(),
                MemberID  = owner.Id,
                ChannelID = talking.Id,

            };

            if (string.IsNullOrEmpty(member.Id))
            {
                return;
            }

            MemberDB.Insert(member);
            Modified();
        }

        public void RemoveMember(Character owner, TalkingBase talking)
        {
            if (owner is null || talking is null)
            {
                return;
            }
            
            var member = MemberDB.FindOne(x => x.MemberID == owner.Id && x.ChannelID == talking.Id);

            if (member is null)
            {
                return;
            }
            
            MemberDB.Delete(member.Id);
            Modified();
        }

        public void RemoveMemberByChannel(TalkingBase talking)
        {
            if (talking is null)
            {
                return;
            }

            var id = talking.Id;

            if (string.IsNullOrEmpty(id))
            {
                return;
            }

            var members = MemberDB.Find(x => x.ChannelID == talking.Id)
                                  .Select(x => x.Id)
                                  .ToHashSet();
            MemberDB.DeleteMany(x => members.Contains(x.Id));
            Modified();
        }
        
        public void RemoveMemberByCharacter(IEnumerable<string> idPool)
        {
            if (idPool is null)
            {
                return;
            }

            var set = idPool.ToHashSet();
            var members = MemberDB.Find(x => set.Contains(x.MemberID))
                                  .Select(x => x.Id)
                                  .ToHashSet();
            MemberDB.DeleteMany(x => members.Contains(x.Id));
            Modified();
        }

        #endregion
        
        
        /// <summary>
        /// 注册组装工厂
        /// </summary>
        /// <param name="map">工厂字典</param>
        void IInstanceAssemblyFactory.Register(IDictionary<Type, IInstanceAssemblyFactory> map)
        {
            map?.Add(typeof(Factory_MSG<Character>), this);
        }
        
        /// <summary>
        /// 取消注册组装工厂
        /// </summary>
        /// <param name="map">工厂字典</param>
        void IInstanceAssemblyFactory.Unregister(IDictionary<Type, IInstanceAssemblyFactory> map)
        {
            map?.Remove(typeof(Factory_MSG<Character>));
        }

        /// <summary>
        /// 实现对消息的装配
        /// </summary>
        /// <param name="msg">要装配的消息</param>
        void IInstanceAssemblyFactory.Assembly(Factory_MSG msg)
        {
            if (msg is not Factory_MSG<Character> msg2)
            {
                return;
            }

            if (string.IsNullOrEmpty(msg2.Id))
            {
                return;
            }

            //
            //
            msg2.Instance = GetCharacter(msg2.Id);
        }

        protected override void OnDatabaseOpening(RepositoryOpenContext context)
        {
            var repo = context.Repository;

            ChannelDB   = repo.Get<TalkingBase>(CollectionNames.TalkingDB);
            MemberDB    = repo.Get<TalkingMember>(CollectionNames.TalkingDB_Member);
            EmojiDB     = repo.Get<Emoji>(CollectionNames.TalkingDB_Emoji);
            
            base.OnDatabaseOpening(context);
        }

        protected override void OnDatabaseClosing(ILogger logger)
        {
            ChannelDB   = null;
            MemberDB    = null;
            EmojiDB     = null;
            
            base.OnDatabaseClosing(logger);
        }


        public override string EngineID => EngineNames.Talking;


        public ILiteCollection<TalkingBase>   ChannelDB   { get; private set; }
        public ILiteCollection<TalkingMember> MemberDB    { get; private set; }
        public ILiteCollection<Emoji>         EmojiDB     { get; private set; }
    }
}